package com.myapi.ModelPoker;
import java.util.*;



/**
 * Calculate the rank of the cards
 * @author Realease by Yoan Olivier
 *
 */
public class RegularCardAnalyser extends CardAnalyser {
		
	
	public RankedHand checkHighCard(Set<Card> cards) {
		//get the highest 5 cards
		Set<Card> treeCards = new TreeSet<Card>(cards);
		Set<Card> highCards = new TreeSet<Card>();		
		Iterator<Card> iter = treeCards.iterator();
		int count = 0;
		while(iter.hasNext()) {
			if(count < 5) {
				Card tempCard = iter.next();
				highCards.add(tempCard);
				count++;
			} else {
				break;
			}
		}
		return new FullHand(HIGHCARD, highCards);
	}
	
	/**
	 * Check Flush rank
	 * TODO : flush card must be the higher cards for exemple 6 cards with the same value
	 */
	public RankedHand checkFlush(Set<Card> cards) {
		int spadeCount = 0;
		int heartCount = 0;
		int clubCount = 0;
		int diamondCount = 0;
		String flushSuit = "";
		TreeSet<Card> treeCards = new TreeSet<Card>(cards);
		Iterator<Card> setIterator = treeCards.iterator();
		while(setIterator.hasNext()) {
			Card card = setIterator.next();
			if(card.getSuit().equals(Card.SPADE))
				spadeCount++;
			else if(card.getSuit().equals(Card.HEART))
				heartCount++;
			else if(card.getSuit().equals(Card.CLUB))
				clubCount++;
			else if(card.getSuit().equals(Card.DIAMOND))
				diamondCount++;
		}
		if(spadeCount >= 5) 
			flushSuit = Card.SPADE;
		else if(heartCount >= 5) 
			flushSuit = Card.HEART;
		else if(clubCount >= 5)
			flushSuit = Card.CLUB;
		else if(diamondCount >= 5)
			flushSuit = Card.DIAMOND;
		
		if(!flushSuit.equals("")) {
			TreeSet<Card> flushCards = new TreeSet<Card>();
			Iterator<Card> flushIterator = treeCards.iterator();
			while(flushIterator.hasNext()) {
				Card tempCard = flushIterator.next();
				if(tempCard.getSuit().equals(flushSuit)) {
					flushCards.add(tempCard);			
				}
				if(flushCards.size() == 5) {  //only get the top 5 flush cards (in case there are more than 5 cards in hand eg HoldEm)
					return new FullHand(FLUSH, flushCards);
				}
			}
		}
		return null;		
	}

	
	public RankedHand checkPair(Set<Card> cards) {
		int lastCardValue = 0;
		Card pairCard = null;
		Set<Card> pairCards = new TreeSet<Card>();
		Set<Card> treeCards = new TreeSet<Card>(cards);
		Iterator<Card> treeIterator = treeCards.iterator();
		if(treeIterator.hasNext()) {
			Card tempCard = treeIterator.next();
			lastCardValue = tempCard.getValue();
			pairCards.add(tempCard);
		}
		while(treeIterator.hasNext()) {
			Card tempCard = treeIterator.next();
			int tempValue = tempCard.getValue();
			if(tempValue == lastCardValue) {
				pairCards.add(tempCard);
				pairCard = tempCard;
				break;
			} else {
				pairCards.clear();
				pairCards.add(tempCard);
			}
			lastCardValue = tempValue;
		}
		if(pairCards.size() == 2) {  //fill the best cards up with the rest of the highest cards
			Iterator<Card> iter = treeCards.iterator();
			while(iter.hasNext()) {
				Card tempCard = iter.next();
				int cardValue = tempCard.getValue();
				if(cardValue != pairCard.getValue() && pairCards.size() < 5) {
					pairCards.add(tempCard);
				}
			}
			return new PartialHand(PAIR, pairCards, pairCard);
		}
		return null;
	}
	
	public RankedHand checkTwoPair(Set<Card> cards) {
		int lastCardValue = 0;
		int pair1Value = 0;
		int pair2Value = 0;
		Card interestCard1 = null;
		Card interestCard2 = null;
		Set<Card> pairCards1 = new TreeSet<Card>();
		Set<Card> pairCards2 = new TreeSet<Card>();
		Set<Card> treeCards = new TreeSet<Card>(cards);
		Iterator<Card> treeIterator = treeCards.iterator();
		if(treeIterator.hasNext()) {
			Card tempCard = treeIterator.next();
			lastCardValue = tempCard.getValue();
			pairCards1.add(tempCard);
		}
		while(treeIterator.hasNext()) {
			Card tempCard = treeIterator.next();
			int tempValue = tempCard.getValue();
			if(tempValue == lastCardValue) {
				pairCards1.add(tempCard);
				pair1Value = tempValue;
				interestCard1 = tempCard;
				break;
				
			} else {
				pairCards1.clear();
				pairCards1.add(tempCard);
			}
			lastCardValue = tempValue;
		}
		if(pairCards1.size() == 2) {
			Iterator<Card> iterator = treeCards.iterator();
			if(iterator.hasNext()) {
				Card tempCard = iterator.next();
				lastCardValue = tempCard.getValue();
				pairCards2.add(tempCard);
			}
			while(iterator.hasNext()) {
				Card tempCard = iterator.next();
				int tempValue = tempCard.getValue();
				if(tempValue == lastCardValue && tempValue != pair1Value) {
					pairCards2.add(tempCard);
					pair2Value = tempValue;
					interestCard2 = tempCard;
					break;
					
				} else {
					pairCards2.clear();
					pairCards2.add(tempCard);
				}
				lastCardValue = tempValue;
			}
		}
		
		pairCards1.addAll(pairCards2);
		
		if(pairCards1.size() == 4) {  //add to 2 pair the highest kicker
			Iterator<Card> iter = treeCards.iterator();
			while(iter.hasNext()) {
				Card tempCard = iter.next();
				int cardValue = tempCard.getValue();
				if(cardValue != pair1Value && cardValue != pair2Value) {
					pairCards1.add(tempCard);
					break;
				}
			}
			return new CombinedHand(TWOPAIR, pairCards1, interestCard1, interestCard2);
		}
		return null;
	}
	
	public RankedHand checkTrips(Set<Card> cards) {
		int lastCardValue = 0;
		int tripValue = 0;
		int count = 1;
		Card tripCard = null;
		Set<Card> tripCards = new TreeSet<Card>();
		Set<Card> treeCards = new TreeSet<Card>(cards);
		Iterator<Card> treeIterator = treeCards.iterator();
		if(treeIterator.hasNext()) {
			Card tempCard = treeIterator.next();
			lastCardValue = tempCard.getValue();
			tripCards.add(tempCard);
		}
		while(treeIterator.hasNext()) {
			Card tempCard = treeIterator.next();
			int tempValue = tempCard.getValue();
			if(tempValue == lastCardValue) {
				tripCards.add(tempCard);
				count++;
				if(count == 3) {
					tripValue = tempValue;
					tripCard = tempCard;
					break;
				}
			} else {
				count = 1;
				tripCards.clear();
				tripCards.add(tempCard);
			}
			lastCardValue = tempValue;
		}
		if(tripCards.size() == 3) {  //fill the best cards up with the rest of the highest cards
			Iterator<Card> iter = treeCards.iterator();
			while(iter.hasNext()) {
				Card tempCard = iter.next();
				int cardValue = tempCard.getValue();
				if(cardValue != tripValue && tripCards.size() < 5) {
					tripCards.add(tempCard);
				}
			}
			return new PartialHand(TRIPS, tripCards, tripCard);
		}
		return null;
	}
	
	public RankedHand checkFourOfKind(Set<Card> cards) {
		int lastCardValue = 0;
		int fourValue = 0;
		int count = 1;
		Card fourCard = null;
		Set<Card> fourCards = new TreeSet<Card>();
		Set<Card> treeCards = new TreeSet<Card>(cards);
		Iterator<Card> treeIterator = treeCards.iterator();
		if(treeIterator.hasNext()) {
			Card tempCard = treeIterator.next();
			lastCardValue = tempCard.getValue();
			fourCards.add(tempCard);
		}
		while(treeIterator.hasNext()) {
			Card tempCard = treeIterator.next();
			int tempValue = tempCard.getValue();
			if(tempValue == lastCardValue) {
				fourCards.add(tempCard);
				count++;
				if(count == 4) {
					fourValue = tempValue;
					fourCard = tempCard;
					break;
				}
			} else {
				count = 1;
				fourCards.clear();
				fourCards.add(tempCard);
			}
			lastCardValue = tempValue;
		}
		if(fourCards.size() == 4) {  //fill the best cards up with the rest of the highest cards
			Iterator<Card> iter = treeCards.iterator();
			while(iter.hasNext()) {
				Card tempCard = iter.next();
				int cardValue = tempCard.getValue();
				if(cardValue != fourValue && fourCards.size() < 5) {
					fourCards.add(tempCard);
				}
			}
			return new PartialHand(FOUROFKIND, fourCards, fourCard);		
		}
		return null;
	}
	
	public RankedHand checkFullHouse(Set<Card> cards) {
		int lastCardValue = 0;
		int matchCount = 1;
		int tripCardValue = 0;
		Card interestCard1 = null;
		Card interestCard2 = null;
		Set<Card> tripCards = new TreeSet<Card>();
		Set<Card> pairCards = new TreeSet<Card>();
		Set<Card> treeCards = new TreeSet<Card>(cards);
		Iterator<Card> treeIterator = treeCards.iterator();
		if(treeIterator.hasNext()) {
			Card tempCard = treeIterator.next();
			lastCardValue = tempCard.getValue();
			tripCards.add(tempCard);
		}
		while(treeIterator.hasNext()) {  //find highest trip cards first
			Card tempCard = treeIterator.next();
			int tempValue = tempCard.getValue();
			if(tempValue == lastCardValue) {
				tripCards.add(tempCard);
				matchCount++;
				if(matchCount == 3) {
					tripCardValue = tempValue;
					interestCard1 = tempCard;
					break;
				}
			}
			else {
				matchCount = 1;
				tripCards.clear();
				tripCards.add(tempCard);
			}
			lastCardValue = tempValue;
		}
		
		if(tripCards.size() == 3) {  //continue if we have found trips so far
			Iterator<Card> pairIterator = treeCards.iterator();
			if(pairIterator.hasNext()) {
				Card tempCard = pairIterator.next();
				lastCardValue = tempCard.getValue();
				pairCards.add(tempCard);
			}
			while(pairIterator.hasNext()) {
				Card tempCard = pairIterator.next();
				int tempValue = tempCard.getValue();
				if(tempValue == lastCardValue && tempValue != tripCardValue) {
					pairCards.add(tempCard);
					matchCount++;
					if(matchCount == 2) {
						interestCard2 = tempCard;
						break;
					}
				}
				else {
					matchCount = 1;
					pairCards.clear();
					pairCards.add(tempCard);
				}
				lastCardValue = tempValue;
			}
			tripCards.addAll(pairCards);
		}
		if(tripCards.size() == 5) {  //if we have also found a pair, we have a fullhouse
			return new CombinedHand(FULLHOUSE, tripCards, interestCard1, interestCard2);
		}
		return null;
	}

	public RankedHand checkStraight(Set<Card> cards) {
		int lastCardValue = 0;
		int conCount = 1;  //the number of consecutive cards
		Set<Card> straightCards = new TreeSet<Card>();  //potential consecutive cards, will be size = 5 if there is a straight
		Set<Card> treeCards = new TreeSet<Card>(cards);
		Iterator<Card> treeIterator = treeCards.iterator();
		if(treeIterator.hasNext()) {
			Card tempCard = treeIterator.next();
			straightCards.add(tempCard);
			lastCardValue = tempCard.getValue();
		}
		while(treeIterator.hasNext()) {
			Card tempCard = treeIterator.next();
			int tempValue = tempCard.getValue();
			//allow for A to be low or high. Only make it low if there are already higher cards in straightCards
			if(tempValue == 14 && straightCards.size() >= 2)
				tempValue = 1;
			
			if(tempValue == lastCardValue - 1)  {  //Cards are arranged in TreeSet in descending order of value
				conCount++;
				straightCards.add(tempCard);
				if(conCount == 5) {  //when we have 5 cards in a row, they are the top 5
					return new FullHand(STRAIGHT, straightCards);
				}
			}
			else {  //broke the consecutive order, clear straightCards and reset count
				straightCards.clear();
				conCount = 1;
				straightCards.add(tempCard);
			}
			lastCardValue = tempValue;
		}
		return null;		
	}

	public RankedHand checkStraightFlush(Set<Card> cards) {
		int lastCardValue = 0;
		String lastCardSuit = "";
		int conCount = 1;  //the number of consecutive cards
		Set<Card> sFCards = new TreeSet<Card>();  //potential consecutive flush cards, will be size = 5 if there is a straight
		Set<Card> treeCards = new TreeSet<Card>(cards);
		Iterator<Card> treeIterator = treeCards.iterator();
		if(treeIterator.hasNext()) {
			Card tempCard = treeIterator.next();
			sFCards.add(tempCard);
			lastCardValue = tempCard.getValue();
			lastCardSuit = tempCard.getSuit();
		}
		while(treeIterator.hasNext()) {
			Card tempCard = treeIterator.next();
			int tempValue = tempCard.getValue();
			String tempSuit = tempCard.getSuit();
			//allow for A to be low or high. Only make it low if there are already higher cards in straightCards
			if(tempValue == 14 && sFCards.size() >= 2)
				tempValue = 1;
			
			if(tempValue == lastCardValue - 1 && tempSuit.equals(lastCardSuit))  {  //Cards are arranged in TreeSet in descending order of value
				conCount++;
				sFCards.add(tempCard);
				if(conCount == 5) {  //when we have 5 cards in a row, they are the top 5
					return new FullHand(STRAIGHTFLUSH, sFCards);
				}
			}
			else {  //broke the consecutive order, clear straightCards and reset count
				sFCards.clear();
				conCount = 1;
				sFCards.add(tempCard);
			}
			lastCardValue = tempValue;
			lastCardSuit = tempSuit;
		}
		return null;
	}

}
